/**
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.frameworkset.commons.dbcp2.managed;
import com.frameworkset.commons.dbcp2.BasicDataSource;
import com.frameworkset.commons.dbcp2.ConnectionFactory;
import com.frameworkset.commons.dbcp2.PoolableConnection;
import com.frameworkset.commons.dbcp2.PoolableConnectionFactory;
import com.frameworkset.commons.dbcp2.PoolingDataSource;
import javax.sql.DataSource;
import javax.sql.XADataSource;
import javax.transaction.TransactionManager;
import java.sql.SQLException;
/**
* <p>BasicManagedDataSource is an extension of BasicDataSource which
* creates ManagedConnections. This data source can create either
* full two-phase-commit XA connections or one-phase-commit
* local connections. Both types of connections are committed or
* rolled back as part of the global transaction (a.k.a. XA
* transaction or JTA Transaction), but only XA connections can be
* recovered in the case of a system crash.
* </p>
* <p>BasicManagedDataSource adds the TransactionManager and XADataSource
* properties. The TransactionManager property is required and is
* used to enlist connections in global transactions. The XADataSource
* is optional and if set is the class name of the XADataSource class
* for a two-phase-commit JDBC driver. If the XADataSource property
* is set, the driverClassName is ignored and a DataSourceXAConnectionFactory
* is created. Otherwise, a standard DriverConnectionFactory is created
* and wrapped with a LocalXAConnectionFactory.
* </p>
*
* @see BasicDataSource
* @see ManagedConnection
* @version $Id: BasicManagedDataSource.java 1649430 2015-01-04 21:29:32Z tn $
* @since 2.0
*/
public class BasicManagedDataSource extends BasicDataSource {
/** Transaction Registry */
private TransactionRegistry transactionRegistry;
/** Transaction Manager */
private transient TransactionManager transactionManager;
/** XA datasource class name */
private String xaDataSource;
/** XA datasource instance */
private XADataSource xaDataSourceInstance;
/**
* Gets the XADataSource instance used by the XAConnectionFactory.
*
* @return the XADataSource
*/
public synchronized XADataSource getXaDataSourceInstance() {
return xaDataSourceInstance;
}
/**
* <p>Sets the XADataSource instance used by the XAConnectionFactory.</p>
* <p>
* Note: this method currently has no effect once the pool has been
* initialized. The pool is initialized the first time one of the
* following methods is invoked: <code>getConnection, setLogwriter,
* setLoginTimeout, getLoginTimeout, getLogWriter.</code></p>
*
* @param xaDataSourceInstance XADataSource instance
*/
public synchronized void setXaDataSourceInstance(XADataSource xaDataSourceInstance) {
this.xaDataSourceInstance = xaDataSourceInstance;
xaDataSource = xaDataSourceInstance == null ? null : xaDataSourceInstance.getClass().getName();
}
/**
* Gets the required transaction manager property.
* @return the transaction manager used to enlist connections
*/
public TransactionManager getTransactionManager() {
return transactionManager;
}
/**
* Gets the transaction registry.
* @return the transaction registry associating XAResources with managed connections
*/
protected synchronized TransactionRegistry getTransactionRegistry() {
return transactionRegistry;
}
/**
* Sets the required transaction manager property.
* @param transactionManager the transaction manager used to enlist connections
*/
public void setTransactionManager(TransactionManager transactionManager) {
this.transactionManager = transactionManager;
}
/**
* Gets the optional XADataSource class name.
* @return the optional XADataSource class name
*/
public synchronized String getXADataSource() {
return xaDataSource;
}
/**
* Sets the optional XADataSource class name.
* @param xaDataSource the optional XADataSource class name
*/
public synchronized void setXADataSource(String xaDataSource) {
this.xaDataSource = xaDataSource;
}
@Override
protected ConnectionFactory createConnectionFactory() throws SQLException {
if (transactionManager == null) {
throw new SQLException("Transaction manager must be set before a connection can be created");
}
// If xa data source is not specified a DriverConnectionFactory is created and wrapped with a LocalXAConnectionFactory
if (xaDataSource == null) {
ConnectionFactory connectionFactory = super.createConnectionFactory();
XAConnectionFactory xaConnectionFactory = new LocalXAConnectionFactory(getTransactionManager(), connectionFactory);
transactionRegistry = xaConnectionFactory.getTransactionRegistry();
return xaConnectionFactory;
}
// Create the XADataSource instance using the configured class name if it has not been set
if (xaDataSourceInstance == null) {
Class<?> xaDataSourceClass = null;
try {
xaDataSourceClass = Class.forName(xaDataSource);
} catch (Exception t) {
String message = "Cannot load XA data source class '" + xaDataSource + "'";
throw new SQLException(message, t);
}
try {
xaDataSourceInstance = (XADataSource) xaDataSourceClass.newInstance();
} catch (Exception t) {
String message = "Cannot create XA data source of class '" + xaDataSource + "'";
throw new SQLException(message, t);
}
}
// finally, create the XAConectionFactory using the XA data source
XAConnectionFactory xaConnectionFactory = new DataSourceXAConnectionFactory(getTransactionManager(), xaDataSourceInstance, getUsername(), getPassword());
transactionRegistry = xaConnectionFactory.getTransactionRegistry();
return xaConnectionFactory;
}
@Override
protected DataSource createDataSourceInstance() throws SQLException {
PoolingDataSource<PoolableConnection> pds =
new ManagedDataSource<PoolableConnection>(getConnectionPool(), transactionRegistry);
pds.setAccessToUnderlyingConnectionAllowed(isAccessToUnderlyingConnectionAllowed());
return pds;
}
/**
* Creates the PoolableConnectionFactory and attaches it to the connection pool.
*
* @param driverConnectionFactory JDBC connection factory created by {@link #createConnectionFactory()}
* @throws SQLException if an error occurs creating the PoolableConnectionFactory
*/
@Override
protected PoolableConnectionFactory createPoolableConnectionFactory(
ConnectionFactory driverConnectionFactory) throws SQLException {
PoolableConnectionFactory connectionFactory = null;
try {
connectionFactory = new PoolableManagedConnectionFactory(
(XAConnectionFactory) driverConnectionFactory, getRegisteredJmxName());
connectionFactory.setValidationQuery(getValidationQuery());
connectionFactory.setValidationQueryTimeout(getValidationQueryTimeout());
connectionFactory.setConnectionInitSql(getConnectionInitSqls());
connectionFactory.setDefaultReadOnly(getDefaultReadOnly());
connectionFactory.setDefaultAutoCommit(getDefaultAutoCommit());
connectionFactory.setDefaultTransactionIsolation(getDefaultTransactionIsolation());
connectionFactory.setDefaultCatalog(getDefaultCatalog());
connectionFactory.setCacheState(getCacheState());
connectionFactory.setPoolStatements(isPoolPreparedStatements());
connectionFactory.setMaxOpenPrepatedStatements(
getMaxOpenPreparedStatements());
connectionFactory.setMaxConnLifetimeMillis(getMaxConnLifetimeMillis());
connectionFactory.setRollbackOnReturn(getRollbackOnReturn());
connectionFactory.setEnableAutoCommitOnReturn(getEnableAutoCommitOnReturn());
connectionFactory.setDefaultQueryTimeout(getDefaultQueryTimeout());
validateConnectionFactory(connectionFactory);
} catch (RuntimeException e) {
throw e;
} catch (Exception e) {
throw new SQLException("Cannot create PoolableConnectionFactory (" + e.getMessage() + ")", e);
}
return connectionFactory;
}
}